package org.jaaksi.demo.ptr.ui.base;

import android.os.Bundle;
import android.view.View;
import android.widget.AbsListView;
import in.srain.cube.views.loadmore.LoadMoreContainer;
import in.srain.cube.views.loadmore.LoadMoreContainerBase;
import in.srain.cube.views.loadmore.LoadMoreDefaultFooterView;
import in.srain.cube.views.loadmore.LoadMoreHandler;
import in.srain.cube.views.loadmore.LoadMoreUIHandler;
import in.srain.cube.views.ptr.*;
import org.jaaksi.demo.ptr.R;
import org.jaaksi.demo.ptr.adapter.BaseListAdapter;
import org.jaaksi.demo.ptr.ptr.footer.DefaultLoadMoreFooterView;
import org.jaaksi.demo.ptr.ptr.header.TaoBaoHeader;
import org.jaaksi.demo.ptr.util.ConstantUtil;
import org.jaaksi.demo.ptr.util.SysUtil;
import org.jaaksi.demo.ptr.view.LoadMoreStateCode;
import org.jaaksi.demo.ptr.view.StateView;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Fcy on 2016/3/16.<br/>
 * 这里使用的LoadMoreStateCode和loadmorecontainer中的完全一致，可以直接使用
 * 待优化点：
 * 1.只使用一个page变量，加载成功后page+1
 * 2.使用StateView太耦合，如果自定义的各种view样式不能用StateView形成那么就会很难处理，
 * 应该提供状态的方法可以让用户自己处理，或返回一个 View，对于base中可以设置StateView状态，然后返回它（是否移除再添加）
 * 3.不能处理有header的情况的StateView的位置，能否借助setEmptyView,如果listview没有数据（第一页），则移除State并setEmptyView
 *
 * TODO
 * 添加header，footer方法，onItemClick方法
 * 可设置禁用下拉刷新，禁用上拉加载
 *
 * @param <D> 数据源
 */
public abstract class BaseAdapterViewActivity<D, L extends AbsListView> extends BaseActivity
  implements LoadMoreStateCode {

  protected int mTotalPages = 0;// 总页数
  protected int mCurrPage = 0;// 当前页
  protected int mLoadPage = 0;// loading的页

  /**
   * 刷新还是加载更多
   */
  protected boolean isRefresh = true;
  // /**
  // * 是否需要下拉刷新
  // */
  // protected boolean isNeedPullRefresh = true;

  protected L mAdapterView;
  /**
   * 下拉刷新控件
   */
  protected PtrClassicFrameLayout mRefreshView;

  // 上拉容器，并不是footerView 替换成loadmoreLayout
  protected LoadMoreContainerBase loadMoreContainer;
  protected LoadMoreUIHandler loadMoreFooter;

  /**
   * 各种状态的view，包括loading,server_error,no_net,no_data
   */
  protected StateView stateView;
  protected List<D> mItems = new ArrayList<D>();
  protected BaseListAdapter<D> mAdapter;
  private View header;

  @Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView();
    mAdapterView = initAdapterView();
    mAdapter = getAdapter();
    // 初始化loadmore footer必须在setAdapter之前调用，否则4.3上不显示
    initLoadMoreView();
    mAdapterView.setAdapter(mAdapter);
    // 这里直接关联adapter与list, 刷新无需再调用adapter的 setDatas,只调用notify即可
    mAdapter.setDatas(mItems);

    mRefreshView = initRefreshView();
    stateView = (StateView) findViewById(R.id.state_view);
    stateView.setOnRetryListener(new View.OnClickListener() {
      @Override public void onClick(View v) {
        loadingRefresh();
        // autoRefresh();
      }
    });
    initChildView();

    // 第一次进来时自动刷新
    if (isAutoLoading()) {
      //			loadingRefresh();
      // 如果使用ptr的autorefresh，不要直接调，建议postdelayed。
      mHandler.postDelayed(new Runnable() {
        @Override public void run() {
          autoRefresh();
        }
      }, 100);
    }
  }

  /**
   * 默认为true，如果需要配置参数然后再加载，那么重写该方法返回false，然后配置参数后手动调用loadingRefresh()方法
   *
   * @return 是否进入列表页后自动加载一次，
   */
  protected boolean isAutoLoading() {
    return true;
  }

  protected abstract void setContentView();

  // protected abstract L initAdapterView();

  protected abstract BaseListAdapter<D> getAdapter();

  protected L initAdapterView() {
    return findViewByIdExt(R.id.list);
  }

  /**
   * 发送请求，在这里调用mDataUtil的请求网络（推荐使用retri+okhttp在成功回调中调用setDatas方法）
   */
  protected abstract void buildRequest();

  /**
   * 子类自定义的部分
   */
  protected void initChildView() {
  }

  protected void autoRefresh() {
    mRefreshView.autoRefresh(true);
  }

  protected final int getTotalPages(int totalNum) {
    return totalNum % getPageSize() == 0 ? (totalNum / getPageSize())
      : (totalNum / getPageSize() + 1);
  }

  /**
   * 加载更多方法，有更多数据时才能调用，可以在成功之后再++而不是在这里++
   */
  protected void loadMore() {
    isRefresh = false;
    // 如果loadmore的时候失败，但是mCurrPage已经++了
    mLoadPage++;
    buildRequest();
  }

  /**
   * 仅仅是不使用hasmore字段的判断
   */
  private boolean hasMoreData() {
    return mLoadPage < mTotalPages;
  }

  protected void refresh() {
    refresh(true);
  }

  /**
   * 刷新方法
   *
   * @param isPullRefresh 是否是下拉刷新
   */
  protected void refresh(boolean isPullRefresh) {
    isRefresh = true;
    mLoadPage = 0;
    mCurrPage = 0;
    mAdapterView.setSelection(0);
    if (isPullRefresh) {
      stateView.setState(StateView.STATE_OTHER);
    } else {
      stateView.setState(StateView.STATE_LOADING);
    }
    buildRequest();
  }

  protected List<D> getItems() {
    return mItems;
  }

  /**
   * 如果没有用hasmore字段，就调用这个方法
   */
  protected void setDatas(List<D> list) {
    if (isRefresh) {
      mItems.clear();
      if (mRefreshView.isRefreshing()) { // ptr的刷新
        mRefreshView.refreshComplete();
      } else {
        loadingClose();
      }
    }
    if (list == null) {
      if (isRefresh) {
        if (!SysUtil.isNetworkAvailable(this)) {
          stateView.setState(StateView.STATE_NO_NET);
        } else {
          stateView.setState(StateView.STATE_SERVER_ERROR);
        }
        loadMoreFinish(STATE_REFRESH, false);
      } else { // 加载更多，证明已经有数据了，并不清空已有数据，不设置error状态
        mLoadPage = mCurrPage;
        // 如果loadmore的时候服务器拿不到数据，就认为hasMore=true
        loadMoreFinish(SysUtil.isNetworkAvailable(this) ? ERROR_SE : ERROR_NET, hasMoreData());
        stateView.setState(StateView.STATE_NORMAL);
      }
    } else if (list.isEmpty() && mItems.isEmpty() && isRefresh) { // 刷新时，没有数据，即0个非null（server异常）
      stateView.setState(StateView.STATE_NO_DATA);
    } else {
      stateView.setState(StateView.STATE_NORMAL);
      mItems.addAll(list);
      if (!isRefresh) {
        mCurrPage++;
      }
      loadMoreFinish(STATE_NORMAL, hasMoreData());
    }
    mAdapter.notifyDataSetChanged();
  }

  /**
   * @param errorCode 错误码{@link LoadMoreStateCode}
   */
  protected void error(int errorCode) {
    if (isRefresh) {
      mItems.clear();
      if (mRefreshView.isRefreshing()) { // ptr的刷新
        mRefreshView.refreshComplete();
      } else {
        loadingClose();
      }
      if (errorCode == LoadMoreStateCode.ERROR_NET) {
        stateView.setState(StateView.STATE_NO_NET);
      } else if (errorCode == LoadMoreStateCode.ERROR_SE) {
        stateView.setState(StateView.STATE_SERVER_ERROR);
      }
      loadMoreFinish(STATE_REFRESH, false);
    } else {
      // 如果是加载更多就证明已经有数据了
      // TODO show footer 网络异常
      mLoadPage = mCurrPage;
      // 如果loadmore的时候服务器拿不到数据，就认为hasMore=true
      loadMoreFinish(errorCode, true);
      stateView.setState(StateView.STATE_NORMAL);
    }

    mAdapter.notifyDataSetChanged();
  }

  /**
   * 服务器异常，这里认为除 normal和netError外都算作serverError
   */
  protected void serverError() {

  }

  /**
   * 网络异常
   */
  protected void netError() {
    if (isRefresh) {
      mItems.clear();
      if (mRefreshView.isRefreshing()) { // ptr的刷新
        mRefreshView.refreshComplete();
      } else {
        loadingClose();
      }
      stateView.setState(StateView.STATE_NO_NET);
      loadMoreFinish(STATE_REFRESH, false);
    } else {
      // 如果是加载更多就证明已经有数据了
      // TODO show footer 网络异常
      mLoadPage = mCurrPage;
      // 如果loadmore的时候服务器拿不到数据，就认为hasMore=true
      loadMoreFinish(ERROR_NET, true);
      stateView.setState(StateView.STATE_NORMAL);
    }

    mAdapter.notifyDataSetChanged();
  }

  /**
   * 如果使用服务器hasmore字段，就必须调用这个方法（推荐使用如果可以）
   *
   * @param list 当数据异常得到的list为null时，setDatas(null)即可
   * @param hasMore 是否有更多（来自服务器的字段）
   */
  protected void setDatas(List<D> list, boolean hasMore) {
    if (isRefresh) {
      mItems.clear();
      if (mRefreshView.isRefreshing()) { // ptr的刷新
        mRefreshView.refreshComplete();
      } else {
        loadingClose();
      }
    }
    if (list == null) {
      if (isRefresh) {
        if (!SysUtil.isNetworkAvailable(this)) {
          stateView.setState(StateView.STATE_NO_NET);
        } else {
          stateView.setState(StateView.STATE_SERVER_ERROR);
        }

        loadMoreFinish(STATE_REFRESH, false);
      } else { // 加载更多，证明已经有数据了，并不清空已有数据，不设置error状态
        mLoadPage = mCurrPage;
        // 如果loadmore的时候服务器拿不到数据，就认为hasMore=true
        loadMoreFinish(SysUtil.isNetworkAvailable(this) ? ERROR_SE : ERROR_NET, true);
        stateView.setState(StateView.STATE_NORMAL);
      }
    } else if (list.isEmpty() && mItems.isEmpty() && isRefresh) { // 刷新时，没有数据，即0个非null（server异常）
      stateView.setState(StateView.STATE_NO_DATA);
    } else {
      stateView.setState(StateView.STATE_NORMAL);
      mItems.addAll(list);
      if (!isRefresh) {
        mCurrPage++;
      }
      loadMoreFinish(STATE_NORMAL, hasMore);
    }
    mAdapter.notifyDataSetChanged();
  }

  /**
   * 这里是通过loadMoreContainer的loadMoreFinish方法，转调给LoadMoreUIHandler
   */
  protected void loadMoreFinish(int errorCode, boolean hasMore) {
    loadMoreContainer.loadMoreFinish(errorCode, hasMore);
  }

  /**
   * 使用loading 进行刷新，需要在结束后手动关闭
   */
  protected void loadingRefresh() {
    refresh(false);
  }

  /**
   * 使用loading 进行刷新，需要在结束后手动关闭
   */
  protected void loadingClose() {
    stateView.setState(StateView.STATE_NORMAL);
  }

  /**
   * @param totalPage
   */
  protected void setTotalPages(int totalPage) {
    mTotalPages = totalPage;
  }

  protected void initTotalPages(int totalNum) {
    mTotalPages = getTotalPages(totalNum);
  }

  protected int getPageSize() {
    return ConstantUtil.PAGE_SIZE;
  }

  protected final int getCurrPage() {
    return mCurrPage;
  }

  protected final int getLoadOffset() {
    return mLoadPage * getPageSize();
  }

  /**
   * @return 自定义header must implements PtrUIHandler
   */
  protected View initPtrHeader() {
    return new TaoBaoHeader(this);
  }

  /**
   * header must implements LoadMoreUIHandler
   */
  protected LoadMoreUIHandler initLoadMoreFooter() {
    //return new DefaultLoadMoreFooterView(this);
    return new LoadMoreDefaultFooterView(this);
  }

  /**
   * @return 下拉时内容是否随着header下拉
   */
  protected boolean isPinContent() {
    return false;
  }

  protected boolean isAutoLoadMore() {
    return true;
  }

  private void initLoadMoreView() {
    loadMoreContainer = findViewByIdExt(R.id.loadmore_view_container);
    // TODO 改为自定义的footer,或者修改arr中默认footer添加loading progressbar
    LoadMoreUIHandler footerView = initLoadMoreFooter();
    //footerView.setVisibility(GONE);
    loadMoreContainer.setLoadMoreView((View) footerView);
    loadMoreContainer.setLoadMoreUIHandler(footerView);
    loadMoreContainer.setAutoLoadMore(isAutoLoadMore());
    loadMoreContainer.setLoadMoreHandler(new LoadMoreHandler() {
      @Override public void onLoadMore(LoadMoreContainer loadMoreContainer) {
        loadMore();
      }
    });
  }

  private PtrClassicFrameLayout initRefreshView() {
    PtrClassicFrameLayout ptr = (PtrClassicFrameLayout) findViewById(R.id.ptr_view);
    // 以下设置大都可在xml中设置
    // 设置阻尼系数
    // ptr.setResistance(1.7f);
    // // 触发刷新时移动的位置比例，默认，1.2f，移动达到头部高度 1.2 倍时可触发刷新操作。
    // // ptr.setRatioOfHeaderHeightToRefresh(1.2f);
    // // 回弹延时，默认 200ms，回弹到刷新高度所用时间
    // ptr.setDurationToClose(200);
    // // 头部回弹时间，默认 1000ms。
    // ptr.setDurationToCloseHeader(1000);
    // // 设置下拉达到高度后自动刷新（默认释放刷新）
    // ptr.setPullToRefresh(false);
    // // 刷新是否保持头部，默认值 true
    // ptr.setKeepHeaderWhenRefresh(true);

    // 设置下拉时内容是否随着header下拉
    ptr.setPinContent(isPinContent());

    // 自定义headerview
    //TaoBaoHeader header = new TaoBaoHeader(this);
    header = initPtrHeader();
    ptr.setHeaderView(header);
    if ((header instanceof PtrUIHandler)) {
      ptr.addPtrUIHandler((PtrUIHandler) header);
    } else {
      throw new IllegalArgumentException("header view must implements PtrUIHandler interface");
    }
    ptr.setPtrHandler(new PtrHandler() {
      @Override
      public boolean checkCanDoRefresh(PtrFrameLayout ptrFrameLayout, View view, View header) {
        return PtrDefaultHandler.checkContentCanBePulledDown(ptrFrameLayout, mAdapterView, header);
      }

      @Override public void onRefreshBegin(PtrFrameLayout ptrFrameLayout) {
        stateView.setState(StateView.STATE_OTHER);
        refresh();
      }
    });
    return ptr;
  }
}
